package net.amsoft.iservice.util;

import static net.amsoft.iservice.util.IServiceConstants.*;
import net.amsoft.iservice.util.FileMonitor;
import net.amsoft.iservice.util.FileChangeListener;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class RedirectionFilter implements Filter, FileChangeListener {
	private static final String PROPERTIES_FILE = "redirector.properties";

	private Hashtable redirectionTargets = null;

	public final static String supportedRegEx = "/(\\(\\+contact\\)|\\(\\+authn\\)|\\(\\+forwarding\\))\\*(\\(\\$v\\*1.0\\))\\/\\(\\!\\![0-9]*\\)";

	private long checkPeriod = REFRESH_INTERVAL;

	public void init(FilterConfig arg0) throws ServletException {
		IServiceUtil.log(INFO, this, "init()=Initializing");
		if (redirectionTargets == null) {
			try {
				redirectionTargets = new Hashtable();
				initFilter(null);
				setCheckPeriod();
			} catch (IOException e) {
				String sMsg = "Invalid properties in property file named:"
						+ PROPERTIES_FILE;
				IServiceUtil.log(ERROR, this, "message=" + sMsg);
				throw new ServletException(sMsg);
			} 
		}
	}

	private void initFilter(String filePath) throws IOException {
		Properties props = new Properties();
		InputStream in;
		if (filePath == null) { // null implies try and load from classpath
			in = getClass().getClassLoader().getResourceAsStream(
					PROPERTIES_FILE);
		} else {
			in = new FileInputStream(filePath);
		}
		IServiceUtil.log(DEBUG, this, "initFilter()", "Message=File read: "
				+ filePath);
		props.load(in);
		in.close();

		Enumeration e = props.propertyNames();
		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			String value = props.getProperty(key);
			redirectionTargets.put(new RedirectorConfig(value), key.trim());
		}
		IServiceUtil.log(DEBUG, this, "initFilter()",
				"Message=File properties read");
	}

	public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc)
			throws IOException, ServletException {
		// try and extract the ?xri=XXXXX param from querystring
		String xri = req.getParameter("xri");
		String path = ((HttpServletRequest) req).getRequestURI();
		// get rid of any trailing slash
		IServiceUtil.log(INFO, this, "doFilter():", "xri=" + xri, "path="
				+ path);
		path = path.replaceAll("/*$", "");
		if(path != null && !path.equals("") && path.matches(supportedRegEx)) {
			RedirectorConfig config = new RedirectorConfig();
			config.populateFromPath(path);
			String url = (String)redirectionTargets.get(config);
			if(url !=null) {
                String sAcceptHeader = ((HttpServletRequest) req).getHeader("Accept");
                
                if(xri != null) {
					url = url + "?xri=" + URLEncoder.encode(xri, "UTF-8");
                    if(sAcceptHeader.contains("text/uri-list"))
                        url = url + "&UriRequest=true"; 
				}else{
                    if(sAcceptHeader.contains("text/uri-list"))
                        url = url + "?UriRequest=true";
                }
                
                //save URI as QP
				HttpServletResponseWrapper r = new HttpServletResponseWrapper((HttpServletResponse)res);
				IServiceUtil.log(INFO, this, "doFilter():",
						"Message=Redirecting to: " + url);
                
                //Set accept header values in session to be used in Checklogin
                
//                ((HttpServletRequest) req).getSession(false).setAttribute(HEADER_ACCEPT, sAcceptHeader);
//                ((HttpServletRequest) req).getSession(false)
//                        .getServletContext().setAttribute(HEADER_ACCEPT,
//                                sAcceptHeader);
                //Redirect after removing un-wanted values from URL(SEP)
				r.sendRedirect(url);
                
			}
			else {
				fc.doFilter( req, res);	
			}
		}
		else {
			fc.doFilter( req, res);	
		}		
	}

	public void destroy() {
		// noop
	}

	public void fileChanged(String fileName, String filePath) {
		Hashtable copy = new Hashtable();
		if (!redirectionTargets.isEmpty()) {
			// make a copy
			copy = (Hashtable) redirectionTargets.clone();
			IServiceUtil.log(INFO, this, "fileChanged():",
					"Message=Making copy of redirection targets.");
		}
		try {
			initFilter(filePath);
		} catch (IOException e) {
			// roll back to the original
			redirectionTargets = copy;
			IServiceUtil.log(ERROR, this, "fileChanged():",
					"could not initialize filter. Filepath=" + filePath,
					" =Doing rollback");
		}
	}

	public synchronized void setCheckPeriod() {
		try {
			FileMonitor.getInstance().addFileChangeListener(this,
					PROPERTIES_FILE, checkPeriod);
		} catch (FileNotFoundException e) {
			IServiceUtil.log(ERROR, this, "setCheckPeriod():",
					"File not found. PROPERTIES_FILE-" + PROPERTIES_FILE,
					"checkPeriod=" + checkPeriod);
		}
	}
}
